//Francisco "Kiko" Olvera
//Handles all game logic
//contains one board and four players
//holds game sound
//Game.h

#include "Game.h"
#include "Controller.h"
#include "input.h"
#include "PowerUp.h"
#include "DirectX.h"
#include "Globals.h"
#include "Text.h"
#include <stdio.h>

Game::Game()
{
}

void Game::Init(Sprite* a_sprite, Input* a_input, int a_numPlayers, int* order)
{
	controller = Controller::Instance();
	numPlayers = a_numPlayers;
	playerOrder = order;
	sprite = a_sprite;
	input = a_input;
	initArtifactsAndCards();
	board.Init(artifact);
	initPlayers();
	board.initLight(numPlayers, order, player);//players need to get initialized 1st
	PlayerTurn = 0;
	turn = PLACE_TILE;
	cardInfo = new SpriteInfo;
	initSounds();
	initPauseScreen();

}

void Game::initSounds()
{
#ifdef USING_SOUND
	Sound.init(NUM_GAME_SOUNDS);
	char* PUName[NUM_GAME_SOUNDS] = 
	{
		"Assets/Sounds/Indianapolis Bob 01.mp3",
		"Assets/Sounds/Indianapolis Bob 02.mp3",
		"Assets/Sounds/Indianapolis Bob 03.mp3",
		"Assets/Sounds/Indianapolis Bob 04.mp3",
		"Assets/Sounds/Indianapolis Bob 05.mp3",
		"Assets/Sounds/mayan 01.mp3",
		"Assets/Sounds/mayan 02.mp3",
		"Assets/Sounds/mayan 03.mp3",
		"Assets/Sounds/mayan 04.mp3",
		"Assets/Sounds/mayan 05.mp3",
		"Assets/Sounds/Conquistador 01.mp3",
		"Assets/Sounds/Conquistador 02.mp3",
		"Assets/Sounds/Conquistador 03.mp3",
		"Assets/Sounds/Conquistador 04.mp3",
		"Assets/Sounds/Conquistador 05.mp3",
		"Assets/Sounds/Clara Koff 01.mp3",
		"Assets/Sounds/Clara Koff 02.mp3",
		"Assets/Sounds/Clara Koff 03.mp3",
		"Assets/Sounds/Clara Koff 04.mp3",
		"Assets/Sounds/Clara Koff 05.mp3",
		"Assets/Sounds/Power_Up.mp3",
	};

	for(int i=0;i<NUM_GAME_SOUNDS;++i)
		Sound.loadNextSound(PUName[i]);
	Sound.loadMusic("Assets/Sounds/Game_Music_2.mp3");
	Sound.playMusic();
#endif
}

void Game::initPauseScreen()
{
	//Initialize the pause screen sprites
	for(int i = 0; i < NUM_PAUSE_SPRITES; i++)
	{
		pauseTexture[i].loadTexture("blackBackground.png");
		pauseTexture[i].setPosOfCenter(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
	}
	//Set the backgrounds color (mainly for the alpha)
	pauseTexture[0].setColor(150, 255, 255, 255);

	//Initialize the pause screen buttons
	for(int i = 0; i < NUM_PAUSE_BUTTONS; i++)
	{
		pauseButton[i].loadTexture("button.png");
		pauseButton[i].setPos(SCREEN_WIDTH / 8, (SCREEN_HEIGHT / 6) * (i + 1) );
	}

	//The selected button
	selectedButton.loadTexture("buttonSelected.png");
	selectedButton.setPos( SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
	selectedButton.setButtonType(RETURN_BUTTON);
}

int Game::pickCard()
{
	//Create a random number to properly give each player a set amount of cards
	int num = (rand() % NUM_CARD_SPRITES);

	//Pick a random card between 1 and 24 that has not already been picked
	while(picked[num])
	{
		//Set a new card to be picked if the current card has already been picked
		num = (rand() % NUM_CARD_SPRITES);
	}

	//Set the picked card to true
	picked[num] = true;

	//Return the selected card number
	return num;
}

void Game::initPlayers()
{
	dealCards();
	for(int i=0;i<numPlayers;++i)
	{
		char* name;
		switch(playerOrder[i])
		{
		case 0:	name = "Assets/Models/Player0.x";	break;
		case 1:	name = "Assets/Models/Player1.x";	break;
		case 2:	name = "Assets/Models/Player2.x";	break;
		case 3:	name = "Assets/Models/Player3.x";	break;
		};

		int dir;
		XY pos;
		Card** deck;
		switch(i)
		{
		case 0:	pos = XY(0);											dir = EAST;		deck = player1Cards; break;
		case 1:	pos = XY(LAST_IN_ROW_OR_COLUMN,0);						dir = SOUTH;	deck = player2Cards; break;
		case 2:	pos = XY(LAST_IN_ROW_OR_COLUMN,LAST_IN_ROW_OR_COLUMN);	dir = WEST;		deck = player3Cards; break;
		case 3:	pos = XY(0,LAST_IN_ROW_OR_COLUMN);						dir = NORTH;	deck = player4Cards; break;
		};

		player[i].Init(name, pos, dir, deck, numCards);
	}
}

void Game::dealCards()
{
	numCards = NUM_ARTIFACTS/numPlayers;
	switch(numPlayers)
	{
	case 2:
		{
			player1Cards = new Card*[numCards];
			player2Cards = new Card*[numCards];
			for(int i=0;i<numCards;++i)
			{
				player1Cards[i] = &card[pickCard()];
				player2Cards[i] = &card[pickCard()];
			}
		}
		break;
	case 3:
		{
			player1Cards = new Card*[numCards];
			player2Cards = new Card*[numCards];
			player3Cards = new Card*[numCards];
			for(int i=0;i<numCards;++i)
			{
				player1Cards[i] = &card[pickCard()];
				player2Cards[i] = &card[pickCard()];
				player3Cards[i] = &card[pickCard()];
			}
		}
		break;
	case 4:
		{
			player1Cards = new Card*[numCards];
			player2Cards = new Card*[numCards];
			player3Cards = new Card*[numCards];
			player4Cards = new Card*[numCards];
			for(int i=0;i<numCards;++i)
			{
				player1Cards[i] = &card[pickCard()];
				player2Cards[i] = &card[pickCard()];
				player3Cards[i] = &card[pickCard()];
				player4Cards[i] = &card[pickCard()];
			}
		}
		break;
	};
}

void Game::initArtifactsAndCards()
{
	art.Load("Assets/Models/Artifact.X", NUM_ARTIFACTS);
	char* ArtCardTextures [] = 
	{
		"Axe.png",
		"Banner.png",
		"Book.png",
		"Bow_and_Arrows.png",
		"coin.png",
		"coinBag.png",
		"Crown.png",
		"Goblet.png",
		"helmet.png",
		"Jewel.png",
		"Key.png",
		"mace.png",
		"necklace.png",
		"pyramid.png",
		"Ring.png",
		"Scroll.png",
		"Skull.png",
		"Spanish_Rifle.png",
		"spear.png",
		"statue.png",
		"Sword.png",
		"torch.png",
		"treasureChest.png",
		"Whip.png",
	};
	for(int i=0;i<NUM_ARTIFACTS;++i)
	{
		artifact[i].Init(i, &art);
		artifact[i].LoadTexture(ArtCardTextures[i]);
		card[i].Load(ArtCardTextures[i], &artifact[i]);
		card[i].GetSpriteInfo()->setScale(0.25);
		picked[i] = 0;
	}
}

void Game::nextPlayer()
{
	turn = PLACE_TILE;
	PlayerTurn++;
	if(PlayerTurn >= numPlayers)
	{
		PlayerTurn = 0;
	}
	int r = rand()%2;

	soundToPlay[controller->CorrectPlayerSound(PlayerTurn, r)] = true;
}
void Game::highlightArtifacts()
{
	//change current tile's material to yellow (highlight tile)
	board.getCurrentTile()->setMatToYellow();
	
	if(input->KeyPressed(DIK_W))
	{
		Tile * tile = board.getN();
		if(tile)
		{
			board.getCurrentTile()->setMatToWhite();
			board.setCurrentTile(tile);
			//loop through every artifact to see if currentTile's artifact matches
			for(int i = 0; i < NUM_ARTIFACTS; ++i)
			{
				//card[i].Flip(false);
				if(board.getCurrentTile()->getArtifact() == &artifact[i])
				{
					//if it does, blit image onto the screen
					card[i].show(true);
					cardInfo = card[i].GetSpriteInfo();
					cardInfo->setScale(0.75f);
					cardInfo->setPosOfCenter(SCREEN_WIDTH*0.5f, SCREEN_HEIGHT*0.5f);
				}
			}
		}
	}
	if(input->KeyPressed(DIK_A))
	{
		Tile * tile = board.getW();
		if(tile)
		{
			board.getCurrentTile()->setMatToWhite();
			board.setCurrentTile(tile);
			//loop through every artifact to see if currentTile's artifact matches
			for(int i = 0; i < NUM_ARTIFACTS; ++i)
			{
				//card[i].Flip(false);
				if(board.getCurrentTile()->getArtifact() == &artifact[i])
				{
					//if it does, blit image onto the screen
					card[i].show(true);
					cardInfo = card[i].GetSpriteInfo();
					cardInfo->setScale(0.75f);
					cardInfo->setPosOfCenter(SCREEN_WIDTH*0.5f, SCREEN_HEIGHT*0.5f);
				}
			}
		}
	}
	if(input->KeyPressed(DIK_S))
	{
		Tile * tile = board.getS();
		if(tile)
		{
			board.getCurrentTile()->setMatToWhite();
			board.setCurrentTile(tile);
			//loop through every artifact to see if currentTile's artifact matches
			for(int i = 0; i < NUM_ARTIFACTS; ++i)
			{
				//card[i].Flip(false);
				if(board.getCurrentTile()->getArtifact() == &artifact[i])
				{
					//if it does, blit image onto the screen
					card[i].show(true);
					cardInfo = card[i].GetSpriteInfo();
					cardInfo->setScale(0.75f);
					cardInfo->setPosOfCenter(SCREEN_WIDTH*0.5f, SCREEN_HEIGHT*0.5f);
				}
			}
		}
	}
	if(input->KeyPressed(DIK_D))
	{
		Tile * tile = board.getE();
		if(tile)
		{
			board.getCurrentTile()->setMatToWhite();
			board.setCurrentTile(tile);
			//loop through every artifact to see if currentTile's artifact matches
			for(int i = 0; i < NUM_ARTIFACTS; ++i)
			{
				//make other cards not show
				//card[i].Flip(false);
				//if current tile's artifact matches an artifact
				if(board.getCurrentTile()->getArtifact() == &artifact[i])
				{
					//if it does, blit image onto the screen
					card[i].show(true);
					cardInfo = card[i].GetSpriteInfo();
					cardInfo->setScale(0.75f);
					cardInfo->setPosOfCenter(SCREEN_WIDTH*0.5f, SCREEN_HEIGHT*0.5f);
				}
			}
		}
	}
}
CONTROLLER_STATE Game::Update()
{
	CameraMove();
	board.Update(input);
	
	gameText.setPosition(0, SCREEN_HEIGHT/10);	  


	if(input->KeyDown(DIK_TAB))
	{
		highlightArtifacts();
	}
	else
	{
		//change material back to white
		board.getCurrentTile()->setMatToWhite();
		////make current tile the same as current player's tile
		//board.setCurrentTile(player[PlayerTurn].getCurrentTile());
		for(int i = 0; i < NUM_ARTIFACTS; ++i)
		{
			card[i].show(false);
		}
	}


	if(player[PlayerTurn].getNumCards() > 0)
	{
		if(input->KeyDown(DIK_LSHIFT) || input->KeyDown(DIK_RSHIFT))
			player[PlayerTurn].ShowCard();
		else
			player[PlayerTurn].HideCard();
	}
	
	switch(turn)
	{
	case PLACE_TILE:
		{
#ifndef TESTING_LIGHTS

			//set instructions
			char buffer[128];
			sprintf_s(buffer,128,"Player %d\nPLACE EXTRA TILE.\nHold <CTRL> for help.", PlayerTurn+1);
			gameText.setText(buffer);
			if(input->KeyDown(DIK_LCONTROL) || input->KeyDown(DIK_RCONTROL))
			{
				gameText.setText(	"* Use <SHIFT> keys to look at your current goal.\n"
									"* Use <TAB> key to look at artifacts on tiles\n"
									"* Use W, A, S, D while holding the <TAB> key to move to a different selected tile\n"
									"* Use A, D, Left arrow, or Right arrow keys to move extra tile.\n"
									"* Use W, S, Up arrow, or Down arrow keys to rotate extra tile.\n"
									"* Use <SPACE> to shift tile into board.\n");
			}

			//moving extra tile
			if(input->KeyPressed(DIK_A) || input->KeyPressed(DIK_LEFT))
				board.shiftExtraPosDown();
			if(input->KeyPressed(DIK_D) || input->KeyPressed(DIK_RIGHT))
				board.shiftExtraPosUp();
			if(input->KeyPressed(DIK_W) || input->KeyPressed(DIK_UP))
				board.RotateExtraTileClock();
			if(input->KeyPressed(DIK_S) || input->KeyPressed(DIK_DOWN))
				board.RotateExtraTileCounterClock();
			//pause the game
			if(input->KeyPressed(DIK_P))
			{
				previousState = turn;
				turn = PAUSE;
			}


			if(input->KeyPressed(DIK_SPACE))
			{
				//shift board
				Tile* newt = board.boardShift();
				//teleport appropriate players
				for(int i=0;i<NUM_PLAYERS;++i)
				{
					if(player[i].getCurrentTile() == board.getExtraTile())
						player[i].SetBoardPosition(newt);
				}
				PowerUp* pow = board.getExtraTile()->getPower();
				if(pow)
				{
#ifdef USING_SOUND
					soundToPlay[POWER_UP_SOUND] = true;
#endif
					power = pow;
					turn = CHOOSE_POWER;
				}
				else
					turn = MOVE_PLAYER;
			}		
#endif
		}
		break;
	case CHOOSE_POWER:
		{
			//create a character buffer
			char buffer[128];
			//add power up name to instructions
			sprintf_s(buffer, 128, "%s\nDo you want to use the power-up? (Y/N)", power->getName());
			gameText.setText(buffer);
			if(input->KeyPressed(DIK_Y))
				turn = USE_POWER;
			if(input->KeyPressed(DIK_N))
			{
				power = NULL;
				turn = MOVE_PLAYER;
			}
			//pause the game
			if(input->KeyPressed(DIK_P))
			{
				previousState = turn;
				turn = PAUSE;
			}

		}
		//turn = MOVE_PLAYER;
		break;
	case USE_POWER:
		{
			int result = power->Execute(input, &player[PlayerTurn], &gameText);
			if(result != STAY)
				power = NULL;
			if(result == MOVE)
				turn = MOVE_PLAYER;
			if(result == NOMOVE)
				turn = CHECK_FOR_WIN;
		}
		break;
	case MOVE_PLAYER:
		{
			//set instructions
			gameText.setText("MOVE PLAYER.\n"
							 "Hold <CTRL> for help.");

			if(input->KeyDown(DIK_LCONTROL) || input->KeyDown(DIK_RCONTROL))
			{
				gameText.setText(	"* Use <SHIFT> keys to look at your current goal.\n"
									"* Use <TAB> key to look at artifacts on tiles\n"
									"* Use W, A, S, D while holding the <TAB> key to move to a different selected tile\n"
									"* Use WASD to move player.\n"
									"* Use <SPACE> to set player position and end turn.\n");
			}

			//TESTING
			if( input->KeyDown(DIK_0) )
			{
				controller->setWinningPlayer(PlayerTurn);
			}

			board.setCurrentTile(player[PlayerTurn].getCurrentTile());
			//player movement
			if(input->KeyPressed(DIK_W) || input->KeyPressed(DIK_UP))
				player[PlayerTurn].MoveNorth();
			if(input->KeyPressed(DIK_A) || input->KeyPressed(DIK_LEFT))
				player[PlayerTurn].MoveWest();
			if(input->KeyPressed(DIK_S) || input->KeyPressed(DIK_DOWN))
				player[PlayerTurn].MoveSouth();
			if(input->KeyPressed(DIK_D) || input->KeyPressed(DIK_RIGHT))
				player[PlayerTurn].MoveEast();
			if(input->KeyPressed(DIK_SPACE))
			{
				if(player[PlayerTurn].Collect())
				{
#ifdef USING_SOUND
					if(player[PlayerTurn].getNumCards() <= 0)
						soundToPlay[controller->CorrectPlayerSound(PlayerTurn, PLAYER_LAST_PICK_UP_SOUND)] = true;
					else
						soundToPlay[controller->CorrectPlayerSound(PlayerTurn, PLAYER_PICK_UP_SOUND)] = true;
				}
#endif
				turn = CHECK_FOR_WIN;
			}
			//For debugging the end game
			if( input->KeyPressed(DIK_0) )
			{
				controller->setWinningPlayer(PlayerTurn);
				return END_GAME;
			}
			//pause the game
			if(input->KeyPressed(DIK_P))
			{
				previousState = turn;
				turn = PAUSE;
			}

		}
		break;
	case CHECK_FOR_WIN:
		{
			if(player[PlayerTurn].getNumCards() <= 0 && player[PlayerTurn].isHome())
			{
				//Set the winning player
				controller->setWinningPlayer(PlayerTurn);
				Sound.playSound(controller->CorrectPlayerSound(PlayerTurn, PLAYER_WIN_SOUND));
 				return END_GAME;
			}
			else
			{
				nextPlayer();
			}
		}
	break;
	case PAUSE:
		{
			//Keyboard input for the pause screen
			if(input->KeyPressed(DIK_P))
			{
				turn = previousState;
			}

			//Mouse input for the pause screen
			//If the mouse is over the return button
			if(pauseButton[0].inButton(input->getMousePosition()))
			{
				//Than if the left mouse button is clicked
				if(input->leftClicked())
				{
					turn = previousState;
				}
			}
			//If the mouse is over the replay button
			if(pauseButton[1].inButton(input->getMousePosition()))
			{
				//Than if the left mouse button is clicked
				if(input->leftClicked())
				{
					Release();

					Init(sprite, input, numPlayers, playerOrder);
				}
			}
			//If the mouse is over the main menu button
			if(pauseButton[2].inButton(input->getMousePosition()))
			{
				//Than if the left mouse button is clicked
				if(input->leftClicked())
				{
					return MENU;
				}
			}
			//If the mouse is over the exit button
			if(pauseButton[3].inButton(input->getMousePosition()))
			{
				//Than if the left mouse button is clicked
				if(input->leftClicked())
				{
					PostQuitMessage(0);
				}
			}
		}
		break;
	};
	controlMusic();
	return GAME;
}

void Game::CameraMove()
{
	DirectXFramework* dx = DirectXFramework::Instance();
	if(dx->getCamMove() == NO_MOVEMENT)
	{
		if(input->KeyPressed(DIK_J))
			dx->moveCameraLeft();
		if(input->KeyPressed(DIK_L))
			dx->moveCameraRight();
		if(input->KeyPressed(DIK_K))
			dx->toggleCameraUp();
	}
}

void Game::controlMusic()
{
	if(input->KeyPressed(DIK_M))
		Sound.toggleMusic();
	if(input->KeyDown(DIK_COMMA))
		Sound.MusicVolumeDown();
	if(input->KeyDown(DIK_PERIOD))
		Sound.MusicVolumeUp();
}

void Game::Render()
{
#ifdef USING_SOUND
	for(int i=0;i<NUM_GAME_SOUNDS;++i)
	{
		if(soundToPlay[i])
			Sound.playSound(i);
		soundToPlay[i] = false;
	}
#endif
	board.Render();
	for(int i=0;i<numPlayers;++i)
	{
		player[i].Draw();
	}
	player[PlayerTurn].DrawCards(sprite);
	
	//blit artifact image on screen
	for(int i = 0; i < NUM_ARTIFACTS; ++i)
	{
		if(card[i].isCardShown())
			sprite->Draw(*cardInfo);
	}

	//If the game is in the pause state
	if(turn == PAUSE)
	{
		RenderPauseScreen();
	}
	else
	{
		gameText.render();
	}
}

void Game::RenderPauseScreen()
{
	//Create a character array for the pause screen button font
	char* buffer[NUM_PAUSE_BUTTONS] =
	{
		"RETURN",
		"RESTART",
		"MAIN MENU",
		"QUIT"
	};

	for(int i = 0; i < NUM_PAUSE_SPRITES; i++)
	{
		sprite->Draw(pauseTexture[i]);
	}
	for(int i = 0; i < NUM_PAUSE_BUTTONS; i++)
	{
		//If the mouse is over the current button
		if(pauseButton[i].inButton(input->getMousePosition()))
		{
			//Set the selected button sprite accordingly
			selectedButton.setPos( pauseButton[i].getSpriteInfo().getPosOfCenter().X, pauseButton[i].getSpriteInfo().getPosOfCenter().Y);
			selectedButton.setButtonType( pauseButton[i].getButtonType() );

			//Draw the selected button sprite
			sprite->Draw( selectedButton.getSpriteInfo() );
		}
		else
		{
			sprite->Draw( pauseButton[i].getSpriteInfo() );
		}

		//Set the button text rectangle
		gameText.setPosAndSize(pauseButton[i].getSpriteInfo().getPosOfCenter().X - pauseButton[i].getSpriteInfo().getCenter().X,		//Left side of the rect
						   pauseButton[i].getSpriteInfo().getPosOfCenter().Y - pauseButton[i].getSpriteInfo().getCenter().Y,		//Top of the rect
						   pauseButton[i].getSpriteInfo().getPosOfCenter().X + pauseButton[i].getSpriteInfo().getCenter().X,		//Right side of the rect
						   pauseButton[i].getSpriteInfo().getPosOfCenter().Y + pauseButton[i].getSpriteInfo().getCenter().Y );		//Bottom of the rect
		//Set the button text
		gameText.setText(buffer[i]);
		//Render the text
		gameText.renderCentered();
	}
}

void Game::Release()
{
#ifdef USING_SOUND
	Sound.Release();
#endif
}